package com.zhangyan.utils;

import com.zhangyan.common.ErrorCode;
import com.zhangyan.exception.BusinessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;

import java.io.IOException;
import java.time.LocalDate;
import java.util.*;


@Component
public class GithubUploader {

    //日志
    private static final Logger LOGGER = LoggerFactory.getLogger(GithubUploader.class);

    //拼接路径时的分隔符
    public static final String URI_SEPARATOR = "/";

    //set集合存放可以上传的图片类型
    public static final Set<String> ALLOW_FILE_SUFFIX = new HashSet<>(Arrays.asList("jpg", "png", "jpeg", "gif"));

    //获取配置中的url赋值给url变量
    @Value("${github.bucket.url}")
    private String url;

    //获取配置中的api赋值给api变量
    @Value("${github.bucket.api}")
    private String api;

    //获取配置中的token赋值给accessToken
    @Value("${github.bucket.access-token}")
    private String accessToken;

    //RestTemplate 是 Spring 提供的一个用于执行 HTTP 请求的工具类
    private final RestTemplate restTemplate;

    //RestTemplateBuilder专门用来构建RestTemplate
    @Autowired
    public GithubUploader(RestTemplateBuilder restTemplateBuilder) {
        this.restTemplate = restTemplateBuilder.build();
    }

    /**
     * 上传文件到Github
     * @return 文件的访问地址
     */
    public String upload(MultipartFile multipartFile) {

        //multipartFile.getOriginalFilename() 获取文件名 即 xxx.xxx
        //getSuffix()获取后缀名
        String suffix = this.getSuffix(multipartFile.getOriginalFilename()).toLowerCase();

        //看这个后缀在集合中有没有
        if (!ALLOW_FILE_SUFFIX.contains(suffix)) {
            throw new IllegalArgumentException("不支持的文件后缀：" + suffix);
        }

        // 重命名文件
        String fileName = UUID.randomUUID().toString().replace("-", "") + "." + suffix;

        // 目录按照日期打散
        String[] folders = this.getDateFolder();

        // 最终的文件路径  用指定分隔符"/"链接
        String filePath = String.join(URI_SEPARATOR, folders) + fileName;

        LOGGER.info("上传文件到Github：{}", filePath);
        //将键值对转为json
        JsonObject payload = new JsonObject();
        payload.add("message", new JsonPrimitive("file upload"));
        try {
            //Base64.getEncoder().encodeToString(multipartFile.getBytes())) 将文件转为base64存到json键值对里面
            payload.add("content", new JsonPrimitive(Base64.getEncoder().encodeToString(multipartFile.getBytes())));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        //创建http请求头对象
        HttpHeaders httpHeaders = new HttpHeaders();
        //set多个键值对
        //请求格式为json   Content-Type:application/json
        httpHeaders.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
        //告诉服务器期望的响应是json Accept : application/json
        httpHeaders.set(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
        //设置token为 Authorization : token ${github.bucket.access-token}
        // GitHub API 要求在请求头中以 token <access_token> 的形式传递访问令牌
        httpHeaders.set(HttpHeaders.AUTHORIZATION, "token " + this.accessToken);

        //RestTemplate对象的exchange方法用于发起http请求
        //this.api + filePath  api是访问github的基础地址  filePath是刚才拼接的路径
        //HttpMethod.PUT 指定请求方式为put请求
        //new HttpEntity<String>(payload.toString(), httpHeaders)  payload 是请求体 httpHeaders是请求头
        //String.class 指定响应体的类型为 String，即返回的响应数据会被解析为字符串
        ResponseEntity<String> responseEntity = this.restTemplate.exchange(this.api + filePath, HttpMethod.PUT,
                new HttpEntity<String>(payload.toString(), httpHeaders), String.class);

        // responseEntity.getStatusCode()获取的是一个类HttpStatusCode
        // 其isError()方法,是判断是否有4开头或者5开头的错误码
        if (responseEntity.getStatusCode().isError()) {
            //responseEntity.getStatusCode() 获取错误码
            String errorMessage = "GitHub API returned an error: " + responseEntity.getStatusCode();
            LOGGER.error(errorMessage);
            throw new BusinessException(ErrorCode.NOT_IMAGE,errorMessage);
        }
        //responseEntity.getBody() 获取响应体
        // JsonParser.parseString(responseEntity.getBody()).getAsJsonObject() 解析json字符串
        JsonObject response = JsonParser.parseString(responseEntity.getBody()).getAsJsonObject();

        LOGGER.info("上传完毕: {}", response.toString());
        return this.url + filePath;
    }

    /**
     * 获取文件的后缀
     * @param fileName
     * @return
     */
    protected String getSuffix(String fileName) {
        //查找字符串中"."最后一次存在的位置
        int index = fileName.lastIndexOf(".");
        if (index != -1) {
            //从"."的后一位开始截取
            String suffix = fileName.substring(index + 1);
            //不为空返回后缀
            if (!suffix.isEmpty()) {
                return suffix;
            }
        }
        //IllegalArgumentException 参数不符合异常
        throw new IllegalArgumentException("非法的文件名称：" + fileName);
    }

    /**
     * 按照年月日获取打散的打散目录
     * yyyy/mmd/dd
     * @return
     */
    protected String[] getDateFolder() {
        String[] retVal = new String[3];

        LocalDate localDate = LocalDate.now();
        retVal[0] = localDate.getYear() + "";

        int month = localDate.getMonthValue();
        retVal[1] = month < 10 ? "0" + month : month + "";

        int day = localDate.getDayOfMonth();
        retVal[2] = day < 10 ? "0" + day : day + "";

        return retVal;
    }
}